package org.gridlab.gridsphere.services.visualization;

import java.io.Writer;
import java.io.IOException;
import java.util.Date;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.PortletContext;
import org.gridlab.gridsphere.services.visualization.DataProvider;

/**
 * Klasa abstrakcyjna zapewniająca możliwość tworzenia wykresów za pomocą różnych technologii i osadzania ich za pomocą kodu html na stronie generowanej przez portlet
 * @author Krzysztof Goj
 */
public abstract class ChartGenerator {
    
    /**
     * Tworzy nowy obiekt typu ChartGenerator
     * @param dp DataProvider z danymi dla tego wykresu
     * @param c Kontekst portletu
     */
    public ChartGenerator(DataProvider dp, PortletContext c) {
        serialNumber = numberOfInstances++;
        dataProvider = dp;
        urlId = "GSVisChart"+serialNumber;
        context = c;
    }
   
    /**
     * Zwraca szerokość generowanego wykresu
     * @return Szerokość generowanego wykresu
     */
    public int getWidth() {return width;}

    /**
     * Zwraca wysokość generowanego wykresu
     * @return Wysokość generowanego wylresu
     */
    public int getHeight() {return height;}

    /**
     * Pobiera wartość zmiennej prywatnej htmlClass
     * @return Wartość zmiennej prywatnej htmlClass
     */
    public String getHtmlClass() {return htmlClass;}

    /**
     * Pobiera wartość zmiennej prywatnej htmlId
     * @return Wartość zmiennej prywatnej htmlId
     */
    public String getHtmlId() {return htmlId;}

    /**
     * Pobiera nazwę generatora wykresów
     * @return Nazwa generatora wykresów
     */
    public String getName() {return name;}

    /**
     * Ustawia szerokość generowanego wykresu
     * @param w Nowa szerokość wykresu
     */
    public void setWidth(int w) {width = w;}

    /**
     * Ustawia wysokość wykresu
     * @param h Nowa wysokość wykresu
     */
    public void setHeight(int h) {height = h;}

    /**
     * Ustawia html-owy atrybut class osadzonego wykresu (aplet lub obrazek)
     * @param c 
     */
    public void setHtmlClass(String c) {htmlClass = c;}

    /**
     * Ustawia nazwę wykresu
     * @param n 
     */
    public void setName(String n) {name = n;}

    /**
     * Ustawia html-owy atrybut id osadzonego wykresu (aplet lub obrazek)
     * @param i 
     */
    public void setHtmlId(String i) {htmlId = i;}

    /**
     * Ustawia część nazwy pliku obrazka.
     * @param i 
     */
    public void setUrlId(String i)  {urlId = i;}
    /**
     * Produkuje kod HTML osadzający wykres
     * @param request 
     * @param response 
     * @throws org.gridlab.gridsphere.services.visualization.ChartGeneratorException 
     * @throws java.io.IOException 
     */
    public abstract void embedChart(RenderRequest request, RenderResponse response) throws ChartGeneratorException, IOException;

    private int serialNumber;
    private static int numberOfInstances = 0;
    private int width=300, height=300; //diamensions of generated chart
    private String htmlClass;
    private String htmlId;
    private String urlId;
    private String name;
    private Date lastGenerated;
    /**
     * DataProvider z danymi dla tego typu wykresu
     */
    protected DataProvider dataProvider;
    /**
     * Kontekst portletu
     */
    protected PortletContext context;

    /**
     * Pobiera część URL-a z danymi dla apletu/obrazkiem.
     */
    protected String getURLNamePart() {return urlId; }
    /**
     * Generuje wykres na podstawie wprowadzonych danych
     * @throws org.gridlab.gridsphere.services.visualization.ChartGeneratorException 
     * @throws java.io.IOException 
     */
    protected abstract void generateChart() throws ChartGeneratorException, IOException;
    /**
     * Funkcja sprawdzająca dane wprowadzane do wizualizacji.
     * W przypadku błędnych danych generuje wyjątek ChartGeneratorException
     * @throws org.gridlab.gridsphere.services.visualization.ChartGeneratorException 
     */
    protected void checkData() throws ChartGeneratorException {
        if(!dataType().isAssignableFrom(dataProvider.getDataType()))
            throw new ChartGeneratorException(new ClassCastException(dataType().getName() + " isn't assignable from " + dataProvider.getDataType().getName()));
    }
    /**
     * 
     * @throws org.gridlab.gridsphere.services.visualization.ChartGeneratorException 
     * @throws java.io.IOException 
     */
    protected void prepare() throws ChartGeneratorException, IOException {
        checkData();
        if(lastGenerated == null || lastGenerated.before(dataProvider.getCreationTime())) {
            generateChart();
            lastGenerated = new Date();
        }
    }
    /**
     * Typ danych akceptowanych przez ten generator
     * @return Typ danych akceptowanych przez ten generator
     */
    protected abstract Class dataType();

    /**
     * Zwraca prawdę jeśli dostarczony data provider jest poprawny
     * @return true jeśli dostarczony data provider jest poprawny, false w przeciwnym przypadku
     */
    public boolean isDataproviderOK() {
        boolean result = true;
        try {checkData();}
        catch(ChartGeneratorException e) { result = false; }

        return result;
    }
}

